/**
 * PC微信聊天应用 - 主服务器文件 (MySQL版本)
 * 集成MySQL数据库、文件上传、消息持久化等功能
 */

// 加载环境变量
require('dotenv').config()

const express = require('express')
const http = require('http')
const socketIo = require('socket.io')
const jwt = require('jsonwebtoken')
const cors = require('cors')
const axios = require('axios')
const path = require('path')

// 导入数据库和模型
const { db } = require('./config/database')
const User = require('./models/User')
const Message = require('./models/Message')
const File = require('./models/File')

// 导入中间件
const { uploadSingle, uploadMultiple, processUploadedFile, uploadAvatar, uploadsPath } = require('./middleware/upload')

// 创建Express应用
const app = express()
const server = http.createServer(app)

// Socket.io配置
const io = socketIo(server, {
  path: '/mychat',
  cors: {
    origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
    methods: ["GET", "POST"],
    credentials: true
  }
})

// 中间件配置
app.use(cors({
  origin: process.env.CORS_ORIGIN || 'http://localhost:5173',
  credentials: true
}))
app.use(express.json({ limit: '10mb' }))
app.use(express.urlencoded({ extended: true, limit: '10mb' }))

// 静态文件服务
app.use('/uploads', express.static(uploadsPath))
app.use('/api/files', express.static(uploadsPath))

// 配置常量
const JWT_SECRET = process.env.JWT_SECRET || '12asdf!@#ABCASD234234ad@)(*&'
const PORT = process.env.PORT || 5000

// 存储在线用户的Socket连接
const onlineUsers = new Map() // userId -> { user, socketId, socket }

// JWT认证中间件
const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'] || req.headers['token']
  const token = authHeader && authHeader.split(' ')[1] || authHeader

  if (!token) {
    return res.status(401).json({ success: false, message: '缺少访问令牌' })
  }

  jwt.verify(token, JWT_SECRET, async (err, decoded) => {
    if (err) {
      return res.status(403).json({ success: false, message: '令牌无效' })
    }
    
    try {
      const user = await User.findById(decoded.id)
      if (!user) {
        return res.status(404).json({ success: false, message: '用户不存在' })
      }
      req.user = user
      next()
    } catch (error) {
      console.error('认证错误:', error)
      res.status(500).json({ success: false, message: '认证失败' })
    }
  })
}

// 机器人回复处理
const handleRobotMessage = async (fromUserId, content, conversationId) => {
  try {
    const robotId = 10 // 机器人用户ID
    
    // 调用图灵机器人API
    const tulingUrl = process.env.TULING_API_URL || 'http://openapi.turingapi.com/openapi/api/v2'
    const postData = {
      "reqType": 0,
      "perception": {
        "inputText": {
          "text": content
        },
        "selfInfo": {
          "location": {
            "city": "北京市",
            "province": "北京",
            "street": "中关村"
          }
        }
      },
      "userInfo": {
        "apiKey": process.env.TULING_API_KEY || "25d308027eb147d6b440b78db3d8ab23",
        "userId": fromUserId.toString()
      }
    }

    let robotReply = "我是大白机器人，很高兴为您服务！"
    
    try {
      const { data } = await axios.post(tulingUrl, postData)
      if (data && data.results && data.results[0] && data.results[0].values) {
        robotReply = data.results[0].values.text
      }
    } catch (apiError) {
      console.error('图灵机器人API调用失败:', apiError.message)
      // 使用默认回复
    }

    // 保存机器人回复到数据库
    const messageData = {
      conversationId,
      fromUserId: robotId,
      toUserId: fromUserId,
      content: robotReply,
      type: 'text'
    }
    
    const messageId = await Message.create(messageData)
    
    // 发送机器人回复
    const userConnection = onlineUsers.get(fromUserId)
    if (userConnection) {
      userConnection.socket.emit('message', {
        id: messageId,
        from: robotId,
        to: fromUserId,
        content: robotReply,
        type: 'text',
        timestamp: new Date().toISOString()
      })
    }
    
  } catch (error) {
    console.error('机器人回复处理错误:', error)
  }
}

// Socket.io连接处理
io.on('connection', (socket) => {
  console.log('新的Socket连接:', socket.id)

  // 用户登录Socket
  socket.on('user_login', async (data) => {
    try {
      console.log('收到用户登录请求:', data)
      const { user, token } = data

      if (!user || !token) {
        console.error('用户信息或token缺失')
        socket.emit('login_error', '用户信息不完整')
        return
      }

      // 验证token
      jwt.verify(token, JWT_SECRET, async (err, decoded) => {
        if (err) {
          console.error('Token验证失败:', err.message)
          socket.emit('login_error', 'Token失效，请重新登录')
          return
        }

        try {
          console.log('Token验证成功，用户ID:', decoded.id)

          // 更新用户在线状态
          await User.updateStatus(user.id, 'online')
          console.log('用户在线状态更新成功')

          // 存储在线用户信息
          onlineUsers.set(user.id, {
            user: user,
            socketId: socket.id,
            socket: socket
          })

          socket.user = user
          console.log(`${user.nickname} Socket连接成功`)

          // 获取用户最近会话列表
          const conversations = await Message.getRecentConversations(user.id)
          socket.emit('conversations', conversations)
          console.log('发送会话列表:', conversations.length, '个会话')

          // 获取未读消息数量
          const unreadCount = await Message.getUnreadCount(user.id)
          socket.emit('unread_count', unreadCount)
          console.log('发送未读消息数量:', unreadCount)

        } catch (error) {
          console.error('用户登录处理错误详情:', error)
          socket.emit('login_error', '登录处理失败: ' + error.message)
        }
      })
    } catch (error) {
      console.error('用户登录错误详情:', error)
      socket.emit('login_error', '登录失败: ' + error.message)
    }
  })

  // 处理消息发送
  socket.on('message', async (data) => {
    try {
      console.log('收到消息:', data)
      const { from, to, content, type = 'text', fileData } = data
      
      // 获取或创建会话
      const conversationId = await Message.getOrCreatePrivateConversation(from, to)
      
      // 创建消息记录
      const messageData = {
        conversationId,
        fromUserId: from,
        toUserId: to,
        content,
        type,
        fileUrl: fileData?.url,
        fileName: fileData?.name,
        fileSize: fileData?.size,
        fileType: fileData?.type
      }
      
      const messageId = await Message.create(messageData)
      
      // 构建完整消息对象
      const fullMessage = {
        id: messageId,
        from,
        to,
        content,
        type,
        fileData,
        timestamp: new Date().toISOString()
      }

      // 查找接收者
      const toUserConnection = onlineUsers.get(to)
      if (toUserConnection) {
        // 在线，直接发送
        toUserConnection.socket.emit('message', fullMessage)
      }
      
      // 发送给发送者确认
      socket.emit('message_sent', {
        messageId,
        timestamp: fullMessage.timestamp
      })

      // 如果是机器人消息，处理AI回复
      if (to === 10) { // 机器人ID
        setTimeout(() => {
          handleRobotMessage(from, content, conversationId)
        }, 1000) // 延迟1秒回复，模拟思考时间
      }
      
    } catch (error) {
      console.error('发送消息错误:', error)
      socket.emit('message_error', '消息发送失败')
    }
  })

  // 获取聊天历史
  socket.on('get_history', async (data) => {
    try {
      const { userId1, userId2, limit = 50, offset = 0 } = data
      const messages = await Message.getPrivateMessages(userId1, userId2, limit, offset)
      socket.emit('chat_history', { messages, userId1, userId2 })
    } catch (error) {
      console.error('获取聊天历史错误:', error)
      socket.emit('history_error', '获取聊天历史失败')
    }
  })

  // 标记消息已读
  socket.on('mark_read', async (data) => {
    try {
      const { conversationId, userId } = data
      await Message.markConversationAsRead(conversationId, userId)
      socket.emit('marked_read', { conversationId })
    } catch (error) {
      console.error('标记已读错误:', error)
    }
  })

  // 连接断开处理
  socket.on('disconnect', async () => {
    if (socket.user) {
      console.log(`${socket.user.nickname} 断开连接`)
      
      try {
        // 更新用户离线状态
        await User.updateStatus(socket.user.id, 'offline')
        
        // 从在线用户列表中移除
        onlineUsers.delete(socket.user.id)
      } catch (error) {
        console.error('处理用户断开连接错误:', error)
      }
    }
  })
})

// 处理Socket.io连接错误
io.on('connection_error', (err) => {
  console.error('Socket.io连接错误:', err)
})

// ==================== REST API 路由 ====================

// 用户登录
app.post('/v1/login', async (req, res) => {
  try {
    const { wxid, password } = req.body

    if (!wxid || !password) {
      return res.status(400).json({
        success: false,
        message: '微信号和密码不能为空'
      })
    }

    // 验证用户凭据
    const user = await User.findByCredentials(wxid, password)

    if (!user) {
      return res.status(401).json({
        success: false,
        message: '微信号或密码错误'
      })
    }

    // 生成JWT token
    const token = jwt.sign(
      { id: user.id, wxid: user.wxid },
      JWT_SECRET,
      { expiresIn: process.env.JWT_EXPIRES_IN || '7d' }
    )

    // 更新最后登录时间
    await User.updateStatus(user.id, 'online')

    res.json({
      success: true,
      message: '登录成功',
      user: {
        id: user.id,
        wxid: user.wxid,
        nickname: user.nickname,
        icon: user.icon,
        sex: user.sex,
        summary: user.summary,
        remark: user.remark,
        area: user.area,
        letter: user.letter,
        robot: user.robot,
        token: token
      }
    })
  } catch (error) {
    console.error('登录错误:', error)
    res.status(500).json({
      success: false,
      message: '登录失败，请稍后重试'
    })
  }
})

// 获取好友列表
app.get('/v1/friends', authenticateToken, async (req, res) => {
  try {
    console.log('收到好友列表请求，用户ID:', req.user.id)
    const friends = await User.getFriends(req.user.id)
    console.log('获取到好友数据:', friends.length, '个好友')
    res.json({
      success: true,
      friends: friends
    })
  } catch (error) {
    console.error('获取好友列表错误:', error)
    res.status(500).json({
      success: false,
      message: '获取好友列表失败'
    })
  }
})

// 搜索用户
app.get('/v1/users/search', authenticateToken, async (req, res) => {
  try {
    const { keyword } = req.query

    if (!keyword) {
      return res.status(400).json({
        success: false,
        message: '搜索关键词不能为空'
      })
    }

    const users = await User.search(keyword, req.user.id)
    res.json({
      success: true,
      users: users
    })
  } catch (error) {
    console.error('搜索用户错误:', error)
    res.status(500).json({
      success: false,
      message: '搜索用户失败'
    })
  }
})

// 获取用户信息
app.get('/v1/users/:id', authenticateToken, async (req, res) => {
  try {
    const userId = parseInt(req.params.id)
    const user = await User.findById(userId)

    if (!user) {
      return res.status(404).json({
        success: false,
        message: '用户不存在'
      })
    }

    res.json({
      success: true,
      user: {
        id: user.id,
        wxid: user.wxid,
        nickname: user.nickname,
        icon: user.icon,
        sex: user.sex,
        summary: user.summary,
        area: user.area,
        robot: user.robot,
        status: user.status
      }
    })
  } catch (error) {
    console.error('获取用户信息错误:', error)
    res.status(500).json({
      success: false,
      message: '获取用户信息失败'
    })
  }
})

// 文件上传
app.post('/v1/upload', authenticateToken, uploadSingle('file'), processUploadedFile, (req, res) => {
  try {
    const uploadedFile = req.uploadedFiles[0]
    res.json({
      success: true,
      message: '文件上传成功',
      file: uploadedFile
    })
  } catch (error) {
    console.error('文件上传错误:', error)
    res.status(500).json({
      success: false,
      message: '文件上传失败'
    })
  }
})

// 多文件上传
app.post('/v1/upload/multiple', authenticateToken, uploadMultiple('files', 5), processUploadedFile, (req, res) => {
  try {
    res.json({
      success: true,
      message: '文件上传成功',
      files: req.uploadedFiles
    })
  } catch (error) {
    console.error('多文件上传错误:', error)
    res.status(500).json({
      success: false,
      message: '文件上传失败'
    })
  }
})

// 头像上传
app.post('/v1/upload/avatar', authenticateToken, uploadAvatar, async (req, res) => {
  try {
    if (!req.file) {
      return res.status(400).json({
        success: false,
        message: '没有上传头像文件'
      })
    }

    // 保存文件信息到数据库
    const fileData = {
      originalName: req.file.originalname,
      storedName: req.file.filename,
      filePath: req.file.path,
      fileSize: req.file.size,
      fileType: 'image',
      mimeType: req.file.mimetype,
      uploadedBy: req.user.id
    }

    await File.create(fileData)

    // 更新用户头像
    await User.update(req.user.id, { icon: req.file.filename })

    res.json({
      success: true,
      message: '头像上传成功',
      avatar: {
        filename: req.file.filename,
        url: `/api/files/images/${req.file.filename}`
      }
    })
  } catch (error) {
    console.error('头像上传错误:', error)
    res.status(500).json({
      success: false,
      message: '头像上传失败'
    })
  }
})

// 获取聊天历史
app.get('/v1/messages/history', authenticateToken, async (req, res) => {
  try {
    const { userId1, userId2, limit = 50, offset = 0 } = req.query

    if (!userId1 || !userId2) {
      return res.status(400).json({
        success: false,
        message: '缺少用户ID参数'
      })
    }

    const messages = await Message.getPrivateMessages(
      parseInt(userId1),
      parseInt(userId2),
      parseInt(limit),
      parseInt(offset)
    )

    res.json({
      success: true,
      messages: messages
    })
  } catch (error) {
    console.error('获取聊天历史错误:', error)
    res.status(500).json({
      success: false,
      message: '获取聊天历史失败'
    })
  }
})

// 搜索消息
app.get('/v1/messages/search', authenticateToken, async (req, res) => {
  try {
    const { keyword, limit = 20 } = req.query

    if (!keyword) {
      return res.status(400).json({
        success: false,
        message: '搜索关键词不能为空'
      })
    }

    const messages = await Message.search(req.user.id, keyword, parseInt(limit))
    res.json({
      success: true,
      messages: messages
    })
  } catch (error) {
    console.error('搜索消息错误:', error)
    res.status(500).json({
      success: false,
      message: '搜索消息失败'
    })
  }
})

// 获取未读消息数量
app.get('/v1/messages/unread', authenticateToken, async (req, res) => {
  try {
    const { conversationId } = req.query
    const unreadCount = await Message.getUnreadCount(
      req.user.id,
      conversationId ? parseInt(conversationId) : null
    )

    res.json({
      success: true,
      unreadCount: unreadCount
    })
  } catch (error) {
    console.error('获取未读消息数量错误:', error)
    res.status(500).json({
      success: false,
      message: '获取未读消息数量失败'
    })
  }
})

// 标记消息已读
app.post('/v1/messages/read', authenticateToken, async (req, res) => {
  try {
    const { conversationId } = req.body

    if (!conversationId) {
      return res.status(400).json({
        success: false,
        message: '缺少会话ID'
      })
    }

    await Message.markConversationAsRead(conversationId, req.user.id)
    res.json({
      success: true,
      message: '消息已标记为已读'
    })
  } catch (error) {
    console.error('标记消息已读错误:', error)
    res.status(500).json({
      success: false,
      message: '标记消息已读失败'
    })
  }
})

// 获取最近会话列表
app.get('/v1/conversations', authenticateToken, async (req, res) => {
  try {
    const { limit = 20 } = req.query
    const conversations = await Message.getRecentConversations(req.user.id, parseInt(limit))

    res.json({
      success: true,
      conversations: conversations
    })
  } catch (error) {
    console.error('获取会话列表错误:', error)
    res.status(500).json({
      success: false,
      message: '获取会话列表失败'
    })
  }
})

// 撤回消息
app.post('/v1/messages/:id/recall', authenticateToken, async (req, res) => {
  try {
    const messageId = parseInt(req.params.id)
    const success = await Message.recall(messageId, req.user.id)

    if (success) {
      res.json({
        success: true,
        message: '消息撤回成功'
      })
    } else {
      res.status(400).json({
        success: false,
        message: '消息撤回失败，可能超过时间限制或无权限'
      })
    }
  } catch (error) {
    console.error('撤回消息错误:', error)
    res.status(500).json({
      success: false,
      message: '撤回消息失败'
    })
  }
})

// 获取文件信息
app.get('/v1/files/:filename', async (req, res) => {
  try {
    const filename = req.params.filename
    const file = await File.findByStoredName(filename)

    if (!file) {
      return res.status(404).json({
        success: false,
        message: '文件不存在'
      })
    }

    res.json({
      success: true,
      file: file
    })
  } catch (error) {
    console.error('获取文件信息错误:', error)
    res.status(500).json({
      success: false,
      message: '获取文件信息失败'
    })
  }
})

// 健康检查接口
app.get('/health', (req, res) => {
  res.json({
    status: 'ok',
    timestamp: new Date().toISOString(),
    uptime: process.uptime(),
    memory: process.memoryUsage(),
    onlineUsers: onlineUsers.size
  })
})

// 404处理
app.use('*', (req, res) => {
  res.status(404).json({
    success: false,
    message: '接口不存在'
  })
})

// 全局错误处理
app.use((error, req, res, next) => {
  console.error('全局错误:', error)
  res.status(500).json({
    success: false,
    message: '服务器内部错误'
  })
})

// ==================== 服务器启动 ====================

// 测试数据库连接并启动服务器
const startServer = async () => {
  try {
    // 测试数据库连接
    const isConnected = await db.testConnection()
    if (!isConnected) {
      console.error('❌ 数据库连接失败，请检查配置')
      process.exit(1)
    }

    // 启动服务器
    server.listen(PORT, () => {
      console.log('🚀 ==========================================')
      console.log('🚀   PC微信聊天应用服务器启动成功!')
      console.log('🚀 ==========================================')
      console.log(`🌐 HTTP服务器: http://localhost:${PORT}`)
      console.log(`🔌 Socket.io路径: /mychat`)
      console.log(`📁 文件上传目录: ${uploadsPath}`)
      console.log(`🗄️  数据库: MySQL (${process.env.DB_NAME || 'pc_wechat_chat'})`)
      console.log(`🔑 JWT密钥: ${JWT_SECRET.substring(0, 10)}...`)
      console.log('🚀 ==========================================')
    })

  } catch (error) {
    console.error('❌ 服务器启动失败:', error)
    process.exit(1)
  }
}

// 优雅关闭处理
const gracefulShutdown = async (signal) => {
  console.log(`\n收到 ${signal} 信号，正在优雅关闭服务器...`)

  try {
    // 关闭HTTP服务器
    server.close(() => {
      console.log('HTTP服务器已关闭')
    })

    // 关闭所有Socket连接
    io.close(() => {
      console.log('Socket.io服务器已关闭')
    })

    // 关闭数据库连接
    await db.close()

    console.log('服务器已优雅关闭')
    process.exit(0)
  } catch (error) {
    console.error('关闭服务器时出错:', error)
    process.exit(1)
  }
}

// 监听进程信号
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'))
process.on('SIGINT', () => gracefulShutdown('SIGINT'))

// 启动服务器
startServer()
